<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use App\Services\TokenService;

class AuthenticateApi
{
    protected $tokenService;

    public function __construct(TokenService $tokenService)
    {
        $this->tokenService = $tokenService;
    }

    /**
     * 从请求中提取 token
     *
     * @param Request $request
     * @return string|null
     */
    protected function extractToken(Request $request): ?string
    {
        $token = $request->bearerToken() ?? $request->header('Authorization');
        
        if ($token && str_starts_with($token, 'Bearer ')) {
            $token = substr($token, 7);
        }

        return $token ?: null;
    }

    public function handle(Request $request, Closure $next): Response
    {
        try {
            $token = $this->extractToken($request);

            if (!$token) {
                return response()->json([
                    'code' => 401,
                    'message' => '未提供认证令牌',
                ], 401);
            }

            $user = JWTAuth::parseToken()->authenticate();
            
            if (!$user) {
                return response()->json([
                    'code' => 401,
                    'message' => '用户不存在',
                ], 401);
            }

            // 检查用户状态（如果用户被禁用，拒绝访问）
            if (!$user->isEnabled()) {
                // 删除该用户的所有token和在线记录
                try {
                    $this->tokenService->removeAll($user->id);
                    \App\Models\OnlineUser::where('user_id', $user->id)->delete();
                } catch (\Exception $e) {
                    \Log::warning('删除禁用用户的Token失败: ' . $e->getMessage());
                }
                
                return response()->json([
                    'code' => 403,
                    'message' => '账户已被禁用',
                ], 403);
            }

            // 验证token是否在Redis中
            if (!$this->tokenService->validate($user->id, $token)) {
                return response()->json([
                    'code' => 401,
                    'message' => '令牌已失效',
                ], 401);
            }

            // 验证IP地址（可选，根据安全策略决定是否启用）
            if (config('auth.token_ip_validation', false)) {
                if (!$this->tokenService->validateIp($user->id, $token, $request->ip())) {
                    // IP不匹配，记录安全事件
                    \Illuminate\Support\Facades\Log::warning('Token IP不匹配', [
                        'user_id' => $user->id,
                        'expected_ip' => $this->tokenService->getTokenInfo($user->id, $token)['ip'] ?? 'unknown',
                        'actual_ip' => $request->ip(),
                    ]);
                    
                    // 根据安全策略，可以选择：
                    // 1. 直接拒绝（更安全）
                    // return response()->json([
                    //     'code' => 401,
                    //     'message' => '令牌IP地址不匹配',
                    // ], 401);
                    // 2. 仅记录日志（更灵活）
                }
            }

            // 刷新token过期时间
            $this->tokenService->refresh($user->id, $token);

            // 更新在线用户的活动时间和在线时长
            try {
                $onlineUser = \App\Models\OnlineUser::where('token', $token)->first();
                if ($onlineUser) {
                    $onlineUser->update([
                        'last_activity_at' => now(),
                    ]);
                    // 更新在线时长
                    $onlineUser->updateOnlineDuration();
                } else {
                    // 如果在线用户记录不存在，创建一条（可能是token复用或记录丢失的情况）
                    try {
                        \App\Models\OnlineUser::create([
                            'user_id' => $user->id,
                            'username' => $user->username,
                            'token' => $token,
                            'ip' => $request->ip(),
                            'user_agent' => $request->userAgent(),
                            'login_at' => now(),
                            'last_activity_at' => now(),
                        ]);
                    } catch (\Exception $createEx) {
                        // 创建失败可能是token已存在（并发情况），尝试更新
                        \Log::debug('创建在线用户记录失败，尝试更新: ' . $createEx->getMessage());
                        try {
                            \App\Models\OnlineUser::where('token', $token)->update([
                                'user_id' => $user->id,
                                'username' => $user->username,
                                'ip' => $request->ip(),
                                'user_agent' => $request->userAgent(),
                                'last_activity_at' => now(),
                            ]);
                        } catch (\Exception $updateEx) {
                            \Log::warning('更新在线用户记录也失败: ' . $updateEx->getMessage());
                        }
                    }
                }
            } catch (\Exception $e) {
                // 更新在线用户失败不影响请求处理
                \Log::warning('更新在线用户信息失败: ' . $e->getMessage());
            }

            auth()->setUser($user);

        } catch (JWTException $e) {
            return response()->json([
                'code' => 401,
                'message' => '令牌无效',
            ], 401);
        }

        return $next($request);
    }
}

